package com.terrapages.wmsc4j.layer;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.terrapages.wmsc4j.bean.BBox;
import com.terrapages.wmsc4j.bean.Pos;
import com.terrapages.wmsc4j.cache.Cache;
import com.terrapages.wmsc4j.layer.resolution.Resolution;
import com.terrapages.wmsc4j.layer.resolution.ResolutionSet;
import com.terrapages.wmsc4j.layer.tile.Tile;
import com.terrapages.wmsc4j.layer.tile.TileFormat;

/**
 * A static layer is a layer that will not write to its cache.
 * Whilst other layers (namly live layer) will retreive a new tile from a WMS
 * and cache it, if the requested tile is no in cache, this Static Layer will not.
 * If the requested tile is not in the StaticLayer's cache, a static image will be returned.
 * 
 * @author mvivian
 *
 */
public class StaticLayer extends AbstractLayer 
{
	private final static Font defaultFont = new Font("Arial",Font.PLAIN,12);
	BufferedImage staticImage;
	
	/**
	 * creates a new Static Layer given an already existing 
	 * StaticLayer and a new set of resolutions and new coverage
	 * 
	 * @param layer
	 * @param resolutions
	 * @param coverage
	 */
	protected StaticLayer(StaticLayer layer, ResolutionSet resolutions, BBox coverage) {
		super(layer, resolutions, coverage);
		this.staticImage = layer.getStaticImage();
	}

	/**
	 * Creates a new Static Layer. 
	 * This constructor allows the static image (given when the a tile is not in cache)
	 * to be set to the image within a given File.
	 * 
	 * @param staticImage
	 * @param resolutions
	 * @param format
	 * @param coverage
	 * @param origin
	 * @param title
	 * @throws IOException if the staticImage File could not be read or interpreted by the Image reader
	 */
	public StaticLayer(final File staticImage, final Cache cache, final ResolutionSet resolutions, final TileFormat format, final BBox coverage, final Pos origin, final String title) throws IOException 
	{
		super(cache,resolutions,format,coverage,origin,title);
		this.staticImage = ImageIO.read(staticImage);
	}
	

	/**
	 * Creates a new Static Layer. 
	 * This constructor uses a default static image (given when the a tile is not in cache).
	 * 
	 * @param cache
	 * @param resolutions
	 * @param tilesize
	 * @param coverage
	 * @param origin
	 * @param title
	 */
	public StaticLayer(final Cache cache, final ResolutionSet resolutions, final TileFormat format, final BBox coverage, final Pos origin, final String title)
	{
		super(cache,resolutions,format,coverage,origin,title);
		
		this.staticImage = new BufferedImage(format.getTileSize().width,format.getTileSize().height,BufferedImage.TYPE_3BYTE_BGR);
		final String message = "Tile not in cache";
		Graphics g = staticImage.getGraphics();
		g.setColor(Color.WHITE);
		g.setFont(defaultFont);
		int mW = g.getFontMetrics().stringWidth(message);
		int mH = g.getFontMetrics().getHeight();
		g.drawString(message, (format.getTileSize().width - mW)/2, (format.getTileSize().height - mH)/2);
	}
	
	/**
	 * <p>Gets a layer that makes iteration useful and easy. The new layer is still essentially "this" Layer,
	 * but with a smaller set of resolutions and a smaller coverage. When you iterate a layer, it will give each tile
	 * in the entire coverage at every zoom level. This can be up to Several Billion Tiles!!
	 * By reducing the coverage and zoom levels you can focus your iterations on a specific sub-set of tiles.</p>
	 * 
	 * <p>When/If you do this, be aware of how you match tiles "zoom" with layer "resolution". 
	 * The new layer has less resolutions, so a resolution that used to correspond to a zoom 
	 * (based on index in resolution set) may now correspond to a different zoom. 
	 * Make use of layer.getResolution() and layer.getZoom(). These will match the zooms and resolutions up
	 * properly.</p>
	 * 
	 * @param coverage
	 * @param minZoom
	 * @param maxZoom
	 * @return A smaller sub-set Layer.
	 */
	public StaticLayer getSubCoverageLayer (BBox extent, int minZoom, int maxZoom)
	{
		final Resolution[] oldResolutions = getResolutions().toArray(new Resolution[this.getResolutions().size()]);
		ResolutionSet newResolutions = new ResolutionSet();
		for(int index = minZoom; index <= maxZoom; index++)
		{
			newResolutions.add(oldResolutions[index]);
		}
		StaticLayer retLayer = new StaticLayer(this,newResolutions,extent);
		return retLayer;
	}

	@Override
	/**
	 * Called when the tile was not in cache.
	 * Gives a static image back in the tile.
	 */
	protected void notInCacheAction(Tile tile) {
		tile.setImage(staticImage);
	}

	public final BufferedImage getStaticImage() {
		return staticImage;
	}
}
